home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************************
- *
- *
- * ObjectMacZapp -- a standard Mac OOP application template
- *
- *
- *
- * ZDragDropWindow.cpp -- the window object with drag and drop
- *
- *
- *
- *
- *
- * © 1996, Graham Cox
- *
- *
- *
- *
- *************************************************************************************************/
-
- #include "ZDragDropWindow.h"
- #include "MacZoop.h"
-
- static pascal OSErr ZWTrackingHandler(DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
- DragReference theDrag);
- static pascal OSErr ZWDropHandler(WindowPtr theWindow, void* refCon, DragReference theDrag);
-
-
-
- static DragTrackingHandlerUPP gDragTrackProc = NewDragTrackingHandlerProc(ZWTrackingHandler);
- static DragReceiveHandlerUPP gDragReceiveProc = NewDragReceiveHandlerProc(ZWDropHandler);
-
-
-
-
- /*--------------------------------*** CONSTRUCTOR ***---------------------------------*/
- /*
-
- create this window object. This has no special initialisation
-
- ----------------------------------------------------------------------------------------*/
-
- ZDragDropWindow::ZDragDropWindow(ZCommander* aBoss, const short windowID)
- : ZWindow(aBoss, windowID)
- {
- }
-
- /*--------------------------------*** DESTRUCTOR ***----------------------------------*/
- /*
-
- remove the handlers, if installed
-
- ----------------------------------------------------------------------------------------*/
-
- ZDragDropWindow::~ZDragDropWindow()
- {
- if (MacHasDM())
- RemoveDragHandlers();
- }
-
-
-
- /*--------------------------------*** INITZWINDOW ***---------------------------------*/
- /*
-
- overridable initialiser. This does the normal initialisation, then installs the handlers
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::InitZWindow()
- {
- inherited::InitZWindow();
-
- if (MacHasDM())
- InstallDragHandlers();
- }
-
-
-
- /*------------------------------------*** DRAG ***------------------------------------*/
- /*
-
- initiate a drag from this window
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::Drag( const Point startPt )
- {
- // this can be called to instigate a drag from this window. When your mouse dragging method
- // wants to perform a drag, it calls this. This then builds the drag region and drag data
- // by calling some additional methods. You can override those methods to implement the drag
- // data, etc you require. <startPt> is in local coordinates, as passed from Click, e.g.
-
- DragReference theDrag;
- RgnHandle dragRgn = NULL;
- unsigned short diCount;
- EventRecord theEvent;
-
- if (MacHasDM())
- {
- // make absolutely sure we are the current port, etc.
-
- Focus();
- FailOSErr(NewDrag(&theDrag));
-
- // add data to the drag
-
- try
- {
- MakeDragData(theDrag);
-
- // if no data was added to the drag (the default case, in fact) do not
- // bother to do anything else
-
- FailOSErr(CountDragItems(theDrag, &diCount));
-
- if (diCount > 0)
- {
- // make a drag region
-
- FailNIL(dragRgn = MakeDragRgn());
-
- // make a dummy event record
-
- theEvent.what = mouseDown;
- theEvent.where = startPt;
- LocalToGlobal(&theEvent.where);
- theEvent.when = TickCount();
- theEvent.message = 0;
- theEvent.modifiers = 0;
-
- // do that drag manager thang!
-
- FailOSErr(TrackDrag(theDrag, &theEvent, dragRgn));
- }
- }
- catch (OSErr err)
- {
- // do not propagate exceptions
- }
-
- DisposeDrag(theDrag);
-
- if (dragRgn)
- DisposeRgn(dragRgn);
- }
- }
-
-
-
- /*--------------------------------*** MAKEDRAGDATA ***--------------------------------*/
- /*
-
- add data to the drag (as much as you want)
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::MakeDragData( const DragReference theDrag )
- {
- // override to add your data to the drag. You will do this normally by using drag manager
- // calls such as AddDragItemFlavor .
-
-
- }
-
-
-
-
- /*--------------------------------*** MAKEDRAGRGN ***---------------------------------*/
- /*
-
- create the drag outline. This uses the content rect by default
-
- ----------------------------------------------------------------------------------------*/
-
- RgnHandle ZDragDropWindow::MakeDragRgn()
- {
- // override to build the drag region you require. By default, the drag region is the content
- // region of the window.
-
- Rect content;
- RgnHandle dragRgn, temp;
- Point origin = {0,0};
-
- FailNIL(dragRgn = NewRgn());
- FailNIL(temp = NewRgn());
-
- GetContentRect(&content);
- RectRgn(dragRgn, &content);
- CopyRgn(dragRgn, temp);
- InsetRgn(temp, 1, 1);
- DiffRgn(dragRgn, temp, dragRgn);
-
- DisposeRgn(temp);
-
- // convert into global corrdinates
-
- LocalToGlobal(&origin);
- OffsetRgn(dragRgn, origin.h, origin.v);
-
- return dragRgn;
- }
-
-
- /*------------------------------------*** DROP ***------------------------------------*/
- /*
-
- Handle the drop from an item in a drag onto this window
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::Drop( const OSType flavour, const Ptr data, const long dataSize)
- {
- // called for each item in a drag for which AcceptsFlavour returns TRUE. The data is already
- // extracted into Ptr and the size of it is given in dataSize. The flavour type allows you
- // to cast the ptr to any expected structure. The default method does nothing- override to
- // implement your own behaviour.
-
- }
-
-
- /*---------------------------------*** DRAGHILITE ***---------------------------------*/
- /*
-
- hilite the window in response to a drag over it
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::DragHilite( const Boolean state, const DragReference theDrag)
- {
- // hilites the window. This uses the drag manager's default hiliting.
-
- RgnHandle dragHiliteRgn;
- Rect content;
-
- Focus();
-
- if (state)
- {
- // make the hilite region
-
- FailNIL(dragHiliteRgn = NewRgn());
-
- GetContentRect(&content);
- RectRgn(dragHiliteRgn, &content);
-
- (void) ShowDragHilite(theDrag, dragHiliteRgn, TRUE);
-
- DisposeRgn(dragHiliteRgn);
- }
- else
- (void) HideDragHilite(theDrag);
-
- }
-
-
- /*----------------------------*** INSTALLDRAGHANDLERS ***-----------------------------*/
- /*
-
- install the procs that call this during a drag
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::InstallDragHandlers()
- {
- // set up the drag handler proc to call this object when a drag occurs over this window. The
- // window's refCon field contains the object reference, so the handler can find this object.
-
- FailOSErr(InstallTrackingHandler(gDragTrackProc, macWindow, 0L));
- FailOSErr(InstallReceiveHandler (gDragReceiveProc, macWindow, 0L));
- }
-
-
- /*----------------------------*** REMOVEDRAGHANDLERS ***------------------------------*/
- /*
-
- get rid of the handlers. This is called by the destructor
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::RemoveDragHandlers()
- {
- // removes the drag handlers when the window is deleted
-
- OSErr theErr;
-
- theErr = RemoveTrackingHandler(gDragTrackProc, macWindow);
- theErr = RemoveReceiveHandler (gDragReceiveProc,macWindow);
- }
-
-
-
- /*------------------------------*** ACCEPTSFLAVOUR ***--------------------------------*/
- /*
-
- return TRUE if this given flavour can be dropped here
-
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZDragDropWindow::AcceptsFlavour( const OSType aFlavour)
- {
- // called with each flavour a drag contains. Return TRUE for each one that can be
- // handled. By default, this simply returns TRUE, indicating that all flavours are
- // accepted. Override to get the behaviour you want.
-
- return TRUE;
- }
-
-
-
- /*--------------------------------*** DROPHANDLER ***---------------------------------*/
- /*
-
- unpacks the data from an accepted drag and passes it to the Drop method.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::DropHandler( const DragReference theDrag )
- {
- // method to dispatch drops from the drag manager. This unpacks the drag data, and for
- // each flavour that the AcceptsFlavour method returns TRUE for, will call Drop with the
- // data of the item.
-
- unsigned short dragItemCount, i;
- unsigned short dragFlavourCount, f;
- ItemReference iRef;
- FlavorType theFlavour;
- Boolean atLeastOneAccepted = FALSE;
- Size dataSize;
- Ptr theData = NULL;
-
- curDragRef = theDrag;
-
- DragHilite(FALSE, theDrag);
- FailOSErr(CountDragItems(theDrag, &dragItemCount));
-
- SetBeachBallCursor();
-
- for (i = 1; i <= dragItemCount; i++)
- {
- // get the item
-
- FailOSErr(GetDragItemReferenceNumber(theDrag, i, &iRef));
-
- // count the flavours in the item
-
- FailOSErr(CountDragItemFlavors(theDrag, iRef, &dragFlavourCount));
-
- // for each flavour, if we can accept the flavour, unpack it and pass the data
- // to the drop method.
-
- for (f = 1; f <= dragFlavourCount; f++)
- {
- FailOSErr(GetFlavorType(theDrag, iRef, f, &theFlavour));
-
- if (AcceptsFlavour(theFlavour))
- {
- // get the data for this object
-
- FailOSErr(GetFlavorDataSize(theDrag, iRef, theFlavour, &dataSize));
-
- // create a buffer big enough to hold the object
-
- FailNIL(theData = NewPtr(dataSize));
-
- // get the data into the buffer
-
- try
- {
- FailOSErr(GetFlavorData(theDrag, iRef, theFlavour, theData, &dataSize, 0L));
-
- // call the method to handle the drop
-
- Drop(theFlavour, theData, dataSize);
- }
- catch(OSErr err)
- {
- if (theData)
- DisposePtr(theData);
-
- theData = NULL;
-
- throw err;
- }
- if (theData)
- DisposePtr(theData);
-
- theData = NULL;
- atLeastOneAccepted = TRUE;
- }
- }
- }
-
- // if nothing in this drag was accepted (unlikely???), throw an error
- // so that the drag manager gives the right feedback
-
- if (! atLeastOneAccepted)
- FailOSErr(paramErr);
-
- curDragRef = NULL;
- }
-
-
-
- /*-------------------------------*** TRACKTHEDRAG ***---------------------------------*/
- /*
-
- dispatches tracking messages to the appropriate method
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZDragDropWindow::TrackTheDrag( const DragTrackingMessage theMessage, const DragReference theDrag)
- {
- // this method handles the tracking of a drag within this window. It calls various other
- // methods to implement its behaviour- normally you would override those where necessary
- // rather than this, which is quite low-level.
-
- curDragRef = theDrag;
-
- switch (theMessage)
- {
- case dragTrackingEnterHandler:
- EnteredHandler(theDrag);
- break;
- case dragTrackingEnterWindow:
- EnteredWindow(theDrag);
- break;
- case dragTrackingInWindow:
- InWindow(theDrag);
- break;
- case dragTrackingLeaveWindow:
- LeftWindow(theDrag);
- break;
- case dragTrackingLeaveHandler:
- LeftHandler(theDrag);
- break;
- }
-
- curDragRef = NULL;
- }
-
- /*------------------------------*** ENTEREDHANDLER ***--------------------------------*/
- /*
-
- the handler was entered
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::EnteredHandler( const DragReference theDrag)
- {
- // default method does nothing
- }
-
-
- /*-------------------------------*** ENTEREDWINDOW ***--------------------------------*/
- /*
-
- the window was made the target of the drag. This hilites it if any flavour in the drag is
- acceptable.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::EnteredWindow( const DragReference theDrag)
- {
- // the drag has enetered this window. If the window accepts any of the flavours in the drag,
- // hilite the window.
-
- unsigned short dragItemCount;
- unsigned short dragFlavourCount;
- ItemReference iRef;
- FlavorType theFlavour;
-
-
-
- FailOSErr(CountDragItems(theDrag, &dragItemCount));
-
- if (dragItemCount)
- {
- do
- {
- // for each drag item, count the flavours
-
- FailOSErr(GetDragItemReferenceNumber(theDrag, dragItemCount, &iRef));
- FailOSErr(CountDragItemFlavors(theDrag, iRef, &dragFlavourCount));
-
- // for each flavour, see if we can accept it. As soon as we get one that we can
- // handle, we hilite the window and exit.
-
- do
- {
- FailOSErr(GetFlavorType(theDrag, iRef, dragFlavourCount, &theFlavour));
-
- if (AcceptsFlavour(theFlavour))
- {
- DragHilite(TRUE, theDrag);
- return;
- }
- }
- while(--dragFlavourCount);
- }
- while(--dragItemCount);
- }
- }
-
-
- /*----------------------------------*** INWINDOW ***----------------------------------*/
- /*
-
- called repeatedly while the drag is over this window
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::InWindow( const DragReference theDrag)
- {
- // called repeatedly as long as the drag is within the window. Override to do other things,
- // such as hilite items within the window, etc.
- }
-
-
- /*---------------------------------*** LEFTWINDOW ***---------------------------------*/
- /*
-
- the drag is no longer in this window. This unhilites the drag here.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZDragDropWindow::LeftWindow( const DragReference theDrag)
- {
- // Ladies and Gentlemen, the drag has left the window. Please leave in an orderly fashion.
-
- DragHilite(FALSE, theDrag);
- }
-
-
- /*--------------------------------*** LEFTHANDLER ***---------------------------------*/
- /*
-
- the drag has left this handler
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZDragDropWindow::LeftHandler( const DragReference theDrag)
- {
- // default method does nothing
- }
-
-
-
-
- /*----------------------------------*** MACHASDM ***----------------------------------*/
- /*
-
- static function returns TRUE if Drag Manager is present. Checks link on PowerMacs.
-
- ----------------------------------------------------------------------------------------*/
-
- Boolean MacHasDM()
- {
- // returns TRUE if drag manager is installed on this mac and is loaded by the CFM.
-
- long gResult;
- OSErr theErr;
- Boolean hasDM = FALSE;
-
- theErr = Gestalt(gestaltDragMgrAttr, &gResult);
-
- if ((theErr == noErr) &&
- (gResult & 1))
- {
- #if GENERATINGCFM
- // check that the dragLib is loaded and linked
-
- hasDM = (NewDrag != (void*) kUnresolvedCFragSymbolAddress);
-
- #else
- hasDM = TRUE;
- #endif
- }
- return hasDM;
- }
-
-
-
- /*--------------------------------*********************---------------------------------*/
- /*
-
- static functions follow. Do not modify them directly- all features can be acessed by
- overriding the appropriate methods.
-
- ----------------------------------------------------------------------------------------*/
-
- static pascal OSErr ZWTrackingHandler(DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
- DragReference theDrag)
- {
- ZDragDropWindow* zdWindow = NULL;
- OSErr theErr = noErr;
-
- // get the object
-
- if (theWindow)
- zdWindow = (ZDragDropWindow*) (GetZWindow(theWindow));
-
- try
- {
- FailNIL(zdWindow);
-
- zdWindow->TrackTheDrag(theMsg, theDrag);
- }
- catch(OSErr err)
- {
- theErr = err;
- }
-
- return theErr;
- }
-
-
- /*--------------------------------*********************---------------------------------*/
-
- static pascal OSErr ZWDropHandler(WindowPtr theWindow, void* refCon, DragReference theDrag)
- {
- ZDragDropWindow* zdWindow = NULL;
- OSErr theErr = noErr;
- // get the object
-
- if (theWindow)
- zdWindow = (ZDragDropWindow*) (GetZWindow(theWindow));
-
- try
- {
- FailNIL(zdWindow);
-
- zdWindow->DropHandler(theDrag);
- }
- catch(OSErr err)
- {
- SysBeep(1);
- theErr = err;
- }
-
- return theErr;
- }
-
- /*--------------------------------*********************---------------------------------*/
-